class TasksController < ApplicationController

  before_filter :find_project, :find_activities

  #Changes task status to approved.
  def approve
    task = Task.find params[:id]
    task.status='Approved'
    task_status_history = TaskStatusHistory.create(:user_id => current_user.id,
      :description => "Approved by #{current_user.login} on #{Date.today}.",
      :task_id => task.id, :changed_to => 'Approved')
    
    if task.save
      task_status_history.save
      flash[:notice]="Task approved successfully."
      redirect_to project_activity_url(task.activity.project_id,task.activity)
    end
  end

  def index
    @tasks = Task.find(:all)
  end

  def show
    @task = Task.find_by_id(params[:id])

    # What is the current status?
    current_status = @task.status
    @status = allowed_status(current_status)
    @task_completed = !@task.end_date.blank?
    @assigned_user = User.find(@task.assigned_to) unless @task.assigned_to.blank?
    @work_unit = Workunit.new(:user => current_user, :task_id => params[:id],
      :worked_at => Time.now.strftime("%m/%d/%Y"))
    @people = @project.members.collect {|user| [user.login, user.id]}
    
    # Remove the current user and add it as the first element to the array
    # for making it the default selection for select helper.
    # In other words, this makes the current user, the default slected user
    # for work hour entry form
    @people = @people.delete_if{|item| item[1] == current_user.id }
    @people = @people.insert(0, [User.find(current_user.id).login, current_user.id])
    @total_working_hours = Workunit.sum(:amount, :conditions => ['task_id = ?',
        params[:id]])

    begin
      @completed_percentage = ( (@task.working_time.to_f /
            @task.projected_time.to_f) * 100 ).to_i
    rescue
      @completed_percentage = 0
    end

    @completed_percentage = @completed_percentage > 100 ? 100 : @completed_percentage
    @activity_logs = ActivityLog.find(:all, :conditions => ['task_id = ?',
        params[:id]], :limit => 5, :order => 'created_at DESC')
  end

  def new_work

    # Start calculating total work hours for the current date and current user.
    reporting_user_id = User.find(params[:user][:id]).id
    work_units_for_current_date_and_user = Workunit.find(:all, :conditions =>
        'DATE_FORMAT(worked_at, \'%Y-%m-%d\') = DATE_FORMAT("' +
        Time.now.strftime("%Y-%m-%d") + '", \'%Y-%m-%d\')AND user_id =' +
        reporting_user_id.to_s + ' AND task_id = ' + params[:work_unit][:task_id])
    total_hours = 0
    work_units_for_current_date_and_user.each {|item| total_hours += item.amount}

    # Only create new work unit if total_hours is less than a day
    if total_hours <= 24 - params[:work_unit][:amount].to_i
      @task = Task.find(params[:work_unit][:task_id])
      @user = User.find params[:user][:id]
      @work_unit = Workunit.new(params[:work_unit].merge(
          :user_id => params[:user][:id], :cost =>
            params[:work_unit][:amount].to_i*@user.hourly_rate.to_i,
        :at_status => @task.status))
      if @work_unit.save
        @project = Project.find_by_id(params[:project_id])
        @activity_user = User.find_by_id(params[:user][:id])
        @activity = ActivityLog.new(:user_id => params[:user][:id],
          :description => "<b>#{@activity_user.login}</b> worked for <b> #{params[
          :work_unit][:amount]} hr(s)</b> on <b>#{@project.name} > #{@task.name}
          </b>, on #{@work_unit.worked_at.strftime('%m/%d/%Y')}",
          :task_id => params[:work_unit][:task_id],
          :workunit_id => @work_unit[:id])
        @activity.save
        redirect_to project_task_url(:project_id => params[:project_id], :id =>
            params[:work_unit][:task_id] ) and return
      else
        redirect_to :action => 'show', :project_id => params[:project_id], :id =>
          params[:work_unit][:task_id], :error => 'num' and return
      end

    else
      redirect_to :action => 'show', :project_id => params[:project_id], :id =>
        params[:work_unit][:task_id], :error => 'max', :error_message =>
        "You can not work more than 24 hours in a day. Can you? Please go to bed \
  now." and return

    end

  end

  def new
    @task = Task.new(:parent_id => params[:parent_id].to_i)
    @people = @project.members.collect {|user| [user.login, user.id]}
    @task.activity_id = params[:activity_id]
  end

  def create
    @task = Task.new(params[:task].merge(:project_id => params[:project_id]))
    @day_hour = params[:day_hour] || []
    @projected_time = params[:task][:projected_time]
    if @projected_time.to_i > 160
      flash[:error] = "Please enter at most 30 days. Tasks should not take more \
 than this."
      render :action => 'new' and return
    else
      # When the user selected days as the time period multiply it with 24 hours
      @task.projected_time = (@projected_time.to_f * 24).to_i if @day_hour.first == "d"
    end
       
    # Setting parent_id to nil means this task is not a subtask,
    # not linked to any task
    # Generally, revisions are linked to other tasks
    @task.parent_id = nil if @task.parent_id == ""

    # Task must be new, not a revision; its revision no is zero (0)
    @task.revision_no = 0
    @task.created_by = current_user.id

    # This is the default status.
    @task.status = "Not started"
    if @task.save
      flash[:notice] = 'Task created successfully'
      redirect_to project_task_url(:id => @task, :project_id => @project) and return
    else
      flash[:error] = "Task can't be created"
      render :action => 'new'
    end

  end

  def edit
    # Variables required for edit.html.erb
    @activity = ActivityLog.find_by_id(params[:activity_id])
    @work_unit = Workunit.find_by_id(@activity[:workunit_id])
    @task = Task.find_by_id(params[:id])
    @people = @project.members.collect {|user| [user.login, user.id]}
    @total_working_hours = Workunit.sum(:amount, :conditions =>
        ['task_id = ?', @task.id])
    @activity_logs = ActivityLog.find(:all, :conditions =>
        ['task_id = ?', @task.id], :limit => 5, :order => 'created_at DESC')

  end

  def update_work
    # Finding current workunit and related workunits (workunits for ancestor tasks)
    @work_units = Workunit.find(:all, :conditions => ["id = ? OR parent_id = ?",
        params[:id], params[:id]])

    # Finding activity log for current workunit
    @activity = ActivityLog.find(
      :first, :conditions => {:workunit_id => params[:id]})

    # Finding user for current activity
    @activity_user = User.find_by_id(params[:user][:id])

    # Finding current task
    @task = Task.find(params[:work_unit][:task_id])

    # Update all related workunit entries
    @work_units.each do |work_unit|
      work_unit[:user_id] = params[:user][:id]
      work_unit[:amount] = params[:work_unit][:amount]
      work_unit[:worked_at] = params[:work_unit][:worked_at]
      unless work_unit.save
        redirect_to :action => 'edit', :project_id => params[:project_id],
          :id => params[:work_unit][:task_id], :activity_id =>
          params[:activity_id], :error => 'num' and return
      end

    end

    # Update activity log
    @activity[:user_id] = params[:user][:id]
    @activity[:description] = "#{@activity_user.login} checked-in \
    #{params[:work_unit][:amount]} hr(s) on #{@project.name} > #{@task.name},
      <br />dated for #{@work_units[0][:worked_at].strftime('%m/%d/%Y')}"

    unless @activity.save
      redirect_to :action => 'edit', :project_id => params[:project_id], :id =>
        params[:work_unit][:task_id], :activity_id => params[:activity_id],
        :error => 'num' and return
    end

    flash[:notice] = 'Workunit and Activity log updated successfully !'
    redirect_to project_task_url(:project_id => params[:project_id], :id =>
        params[:work_unit][:task_id] ) and return

  end

  def destroy

    # Find activity log
    @activity = ActivityLog.find_by_id(params[:activity_id])

    # Find realted workunit entries
    @work_units = Workunit.find(:all, :conditions => ["id = ? OR parent_id = ?",
        @activity.workunit_id, @activity.workunit_id])

    # Delete activity and related workunit entries
    begin
      @activity.destroy
      @work_units.each {|work_unit| work_unit.destroy}
      flash[:notice] = 'Working hours log deleted successfully !'
      redirect_to :back
    rescue
      redirect_to :action => 'show', :project_id => params[:project_id], :id =>
        params[:work_unit][:task_id], :error => 'num' and return
    end

  end

  def change_status
    task = Task.find(:first, :conditions => ["id = ?", params[:id]])
    unless task.status.eql?(params[:task][:status])
      if params[:task][:status] == "In Revision"
        if params[:task_status_history][:description].to_s.blank?
          flash[:error] = "Description field cannot be left blank when you \
          change the status to \"In Revision\""
          redirect_to :action => 'show', :project_id => params[:project_id], :id =>
            params[:id] and return
        end
      end
      task.status = params[:task][:status]
      task_status_history = TaskStatusHistory.create(:user_id => current_user.id,
        :description => params[:task_status_history][:description],
        :task_id => task.id, :changed_to => params[:task][:status])
      if task.status == "Approved"
        task.end_date = Time.today
      end
      task.save
      task_status_history.save
    end
    redirect_to :action => 'show', :project_id => params[:project_id], :id =>
      params[:id]

  end

  def complete_task

    # Find active task
    @tasks = Task.find(:all, :conditions => ["id = ?", params[:id]])

    # Complete is selected, find descendent tasks and mark them as completed
    unless params[:completed].blank?
      @tasks.each do |task|
        @child_tasks = Task.find(:all, :conditions => ["parent_id = ?",
            task[:id]])

        unless @child_tasks.empty?
          @child_tasks.each {|child_task| @tasks << child_task}
        end

        task[:end_date] = Time.now
        task.save
      end
      
      # Complete is unselected, find ancestors and mark them as uncompleted
    else
      @tasks.each do |task|
        @parent_tasks = Task.find(:all, :conditions => ["id = ?",
            task[:parent_id]])

        unless @parent_tasks.empty?
          @parent_tasks.each {|parent_task| @tasks<<parent_task}
        end

        task[:end_date] = nil
        task.save
      end

    end

    redirect_to :action => 'show', :project_id => params[:project_id],
      :id => params[:id]
  end

  private

  def find_project
    @project = Project.find_by_id(params[:project_id])
  end

  def find_activities
    @project_phases = @project.activities # unless @project_phases.blank?
  end

  # Each status has dependency on the other status. For example, in order to
  # change status to "Revision" it has to be set to "Completed" first.

  def allowed_status(current_status)

    case current_status
    when "Not started" then
      ["Not started", "In Progress", "Cancelled"]
    when "Waiting for Approval" then
      ["Waiting for Approval", "Approved", "In Progress", "Cancelled", "Suspended"]
    when "Approved" then
      ["Approved", "In Revision" ]
    when "In Progress" then
      ["In Progress", "Waiting for Approval", "Cancelled", "Suspended"]
    when "Cancelled" then
      ["Cancelled", "In Progress"]
    when "In Revision" then
      ["In Revision", "Waiting for Approval", "Cancelled", "Suspended"]
    when "Completed" then
      ["Completed", "In Revision"]
    when "Suspended" then
      ["Suspended", "In Progress", "Cancelled" ]
    else
      ["Not started"]
    end

  end
end